package com.spzx.product.service.impl;

import com.alibaba.nacos.client.naming.utils.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.spzx.common.core.exception.ServiceException;
import com.spzx.product.api.domain.Product;
import com.spzx.product.api.domain.ProductDetails;
import com.spzx.product.api.domain.ProductSku;
import com.spzx.product.api.domain.SkuQuery;
import com.spzx.product.api.domain.vo.SkuLockVo;
import com.spzx.product.api.domain.vo.SkuPriceVo;
import com.spzx.product.api.domain.vo.SkuStockVo;
import com.spzx.product.domain.SkuStock;
import com.spzx.product.mapper.ProductDetailsMapper;
import com.spzx.product.mapper.ProductMapper;
import com.spzx.product.mapper.ProductSkuMapper;
import com.spzx.product.mapper.SkuStockMapper;
import com.spzx.product.service.ProductService;
import com.spzx.product.service.ProductSkuService;
import com.spzx.product.service.SkuStockService;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 商品 服务实现类
 * </p>
 *
 * @author atguigu
 * @since 2024-10-26
 */
@Service
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {


    @Autowired
    private ProductSkuService productSkuService;

    @Autowired
    private SkuStockService skuStockService;

    @Autowired
    private ProductDetailsMapper productDetailsMapper;

    @Autowired
    private ProductSkuMapper productSkuMapper;

    @Autowired
    private SkuStockMapper skuStockMapper;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public List<Product> getPageList(Product product) {
        return baseMapper.getPageList(product);
    }

    @Override
    public int saveProduct(Product product) {
        //调用自带的方法保存商品信息
        baseMapper.insert(product);

        //获取商品Sku信息
        List<ProductSku> productSkuList = product.getProductSkuList();
        //创建一个保存ProductSku对象进行批量保存的集合
        List<ProductSku> saveProductSkuList = new ArrayList<>();

        //遍历所有获取的ProductSku
        for (int i = 0; i < productSkuList.size(); i++) {
            //获取ProductSku对象
            ProductSku productSku = productSkuList.get(i);
            //获取商品id
            Long productId = product.getId();
            //设置商品id
            productSku.setProductId(productId);
            //设置sku_code
            productSku.setSkuCode(productId + "_" + i);
            //设置sku_Name
            productSku.setSkuName(product.getName() + "_" + productSku.getSkuSpec());
            //设置状态值
            productSku.setStatus(0);
            //将ProductSku放到集合中
            saveProductSkuList.add(productSku);
        }
        //批量保存
        productSkuService.saveBatch(saveProductSkuList);

        //创建一个保存SkuStock象进行批量保存的集合
        List<SkuStock> skuStockList = new ArrayList<>();
        //遍历所有已经保存之后的ProductSku
        for (int i = 0; i < saveProductSkuList.size(); i++) {
            //获取ProductSku
            ProductSku productSku = saveProductSkuList.get(i);
            //创建SkuStock对象
            SkuStock skuStock = new SkuStock();
            //设置skuId
            skuStock.setSkuId(productSku.getId());
            //设置状态值
            skuStock.setStatus(0);
            //获取商品的库存
            Integer stockNum = productSku.getStockNum();
            //设置可用的库存数量
            skuStock.setAvailableNum(stockNum);
            //设置总的库存数量
            skuStock.setTotalNum(stockNum);
            //设置锁定的库存数量
            skuStock.setLockNum(0);
            //设置销量
            skuStock.setSaleNum(0);
            //将SkuStock对象添加到集合中
            skuStockList.add(skuStock);
        }
        //批量保存库存数据
        skuStockService.saveBatch(skuStockList);

        //获取商品图片详情地址
        List<String> detailsImageUrlList = product.getDetailsImageUrlList();
        //将商品图片详情地址使用逗号分隔并转换为字符串
        String detailsImageUrlStr = String.join(",", detailsImageUrlList);
        //创建ProductDetails对象
        ProductDetails productDetails = new ProductDetails();
        //设置商品id
        productDetails.setProductId(product.getId());
        //设置图片详情地址
        productDetails.setImageUrls(detailsImageUrlStr);
        //保存图片详情
        productDetailsMapper.insert(productDetails);

        return 1;
    }

    @Override
    public Product getProductById(Long id) {
        //调用自带的方法根据id查询商品信息
        Product product = this.getById(id);
        //根据商品id查询商品Sku信息
        List<ProductSku> productSkuList = productSkuService.list(new LambdaQueryWrapper<ProductSku>().eq(ProductSku::getProductId, id));
        //遍历所有的商品Sku
        productSkuList.forEach(productSku -> {
            //根据商品Sku的id查询库存表获取库存对象
            SkuStock skuStock = skuStockService.getOne(new LambdaQueryWrapper<SkuStock>().eq(SkuStock::getSkuId, productSku.getId()));
            //设置商品库存
            productSku.setStockNum(skuStock.getTotalNum());
        });
        //将商品Sku信息设置到商品中
        product.setProductSkuList(productSkuList);
        //根据商品id获取商品图片详情
        ProductDetails productDetails = productDetailsMapper.selectOne(new LambdaQueryWrapper<ProductDetails>().eq(ProductDetails::getProductId, id));
        //获取图片详情地址
        String imageUrls = productDetails.getImageUrls();
        //将字符串地址转换为数组
        String[] split = imageUrls.split(",");
        //将数组转换为集合
        List<String> detailsImageUrlList = Arrays.asList(split);
        //将图片详情地址设置到商品中
        product.setDetailsImageUrlList(detailsImageUrlList);
        return product;
    }

    @Override
    public void updateProductById(Product product) {
        //调用自带的根据id更新的方法更新商品信息
        baseMapper.updateById(product);
        //获取所有的商品Sku
        List<ProductSku> productSkuList = product.getProductSkuList();
        //遍历
        productSkuList.forEach(productSku -> {
            //根据id更新商品Sku信息
            productSkuService.updateById(productSku);
            //获取商品Sku的id
            Long skuId = productSku.getId();
            //根据skuId查询SkuStock对象
            SkuStock skuStock = skuStockService.getOne(new LambdaQueryWrapper<SkuStock>().eq(SkuStock::getSkuId, skuId));
            //设置总库存和可用的库存
            skuStock.setTotalNum(productSku.getStockNum());
            skuStock.setAvailableNum(productSku.getStockNum() - skuStock.getLockNum());
            //调用自带的根据id更新的方法
            skuStockService.updateById(skuStock);
        });
        //获取修改之后的商品图片详情地址
        List<String> detailsImageUrlList = product.getDetailsImageUrlList();
        //将新的图片详情地址集合转换为字符串
        String detailsImageUrlStr = String.join(",", detailsImageUrlList);
        //根据商品id查询商品图片详情
        ProductDetails productDetails = productDetailsMapper.selectOne(new LambdaQueryWrapper<ProductDetails>().eq(ProductDetails::getProductId, product.getId()));
        //设置新的图片详情地址
        productDetails.setImageUrls(detailsImageUrlStr);
        //调用自带的根据id更新的方法
        productDetailsMapper.updateById(productDetails);
    }

    @Override
    public void deleteProductByIds(List<Long> ids) {
        //调用自带的方法删除商品信息
        baseMapper.deleteBatchIds(ids);
        //获取所有的商品Sku
        List<ProductSku> productSkuList = productSkuService.list(new LambdaQueryWrapper<ProductSku>().in(ProductSku::getProductId, ids));
        //遍历所有的商品Sku
        productSkuList.forEach(productSku -> {
            //删除商品Sku信息
            productSkuService.removeById(productSku.getId());
            //根据skuId删除库存信息
            skuStockService.remove(new LambdaQueryWrapper<SkuStock>().eq(SkuStock::getSkuId, productSku.getId()));
        });
        //根据商品id删除图片详情信息
        productDetailsMapper.delete(new LambdaQueryWrapper<ProductDetails>().in(ProductDetails::getProductId, ids));
    }

    @Override
    public void updateAuditStatusById(Long id, Integer auditStatus) {
        //创建一个没有任何属性值的Product对象
        Product product = new Product();
        //设置主键
        product.setId(id);
        //设置设置状态值
        product.setAuditStatus(auditStatus);
        //判断是审核通过了还是审核驳回了
        if (auditStatus == 1) {
            //审核通过的成功消息
            product.setAuditMessage("审核通过");
        } else if (auditStatus == -1) {
            //审核驳回消息
            product.setAuditMessage("审核驳回");
        } else {
            //非法参数
            throw new ServiceException("审核状态值非法");
        }
        //调用根据id更新的方法
        baseMapper.updateById(product);
    }

    @Override
    public void updateStatusById(Long id, Integer status) {
        //创建Product对象
        Product product = new Product();
        //设置主键
        product.setId(id);
        //设置商品状态
        product.setStatus(status);
        //调用自带的根据id更新的方法
        baseMapper.updateById(product);
        //根据商品id查询所有的商品Sku
        List<ProductSku> productSkuList = productSkuService.list(new LambdaQueryWrapper<ProductSku>().eq(ProductSku::getProductId, id));
        //遍历
        productSkuList.forEach(productSku -> {
            if (status == 1) {
                //获取布隆过滤器
                RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter("sku:bloom:filter");
                bloomFilter.add(productSku.getId());
            }
            //设置商品Sku的状态
            productSku.setStatus(status);
            //调用自带的根据id更新的方法
            productSkuService.updateById(productSku);
            //根据skuId更新商品库存表中的状态
            skuStockService.update(new LambdaUpdateWrapper<SkuStock>().eq(SkuStock::getSkuId, productSku.getId()).set(SkuStock::getStatus, status));
        });
    }

    @Override
    public List<ProductSku> getTopSale() {
        return productSkuMapper.selectTopSale();
    }

    @Override
    public List<ProductSku> selectProductSkuList(SkuQuery skuQuery) {
        return productSkuMapper.selectProductSkuList(skuQuery);
    }

    @Override
    public SkuPriceVo getSkuPrice(Long skuId) {
        //调用自带的方法获取ProductSku信息
        ProductSku productSku = productSkuMapper.selectOne(
                new LambdaQueryWrapper<ProductSku>()
                        .eq(ProductSku::getId, skuId)
                        .select(ProductSku::getSalePrice, ProductSku::getMarketPrice));
        //创建SkuPriceVo对象
        SkuPriceVo skuPriceVo = new SkuPriceVo();
        //设置属性值
        skuPriceVo.setMarketPrice(productSku.getMarketPrice());
        skuPriceVo.setSalePrice(productSku.getSalePrice());
        skuPriceVo.setSkuId(skuId);
        return skuPriceVo;
    }

    @Override
    public ProductDetails getProductDetails(Long id) {
        //根据商品id获取商品详情
        return productDetailsMapper.selectOne(
                new LambdaQueryWrapper<ProductDetails>()
                        .eq(ProductDetails::getProductId, id)
        );
    }

    @Override
    public Map<String, Long> getSkuSpecValue(Long id) {
        //根据商品id获取商品规Sku信息
        List<ProductSku> productSkuList = productSkuMapper.selectList(
                new LambdaQueryWrapper<ProductSku>()
                        .eq(ProductSku::getProductId, id)
                        .select(ProductSku::getId, ProductSku::getSkuSpec));
        //创建一个返回的Map
        Map<String, Long> skuSpecValueMap = new HashMap<>();
        productSkuList.forEach(item -> {
            skuSpecValueMap.put(item.getSkuSpec(), item.getId());
        });
        return skuSpecValueMap;
    }

    @Override
    public SkuStockVo getSkuStock(Long skuId) {
        //根据skuId获取SkuStock
        SkuStock skuStock = skuStockMapper.selectOne(
                new LambdaQueryWrapper<SkuStock>()
                        .eq(SkuStock::getSkuId, skuId)
                        .select(SkuStock::getAvailableNum, SkuStock::getSaleNum)
        );
        //创建SkuStockVo对象
        SkuStockVo skuStockVo = new SkuStockVo();
        skuStockVo.setAvailableNum(skuStock.getAvailableNum());
        skuStockVo.setSaleNum(skuStock.getSaleNum());
        skuStockVo.setSkuId(skuId);
        return skuStockVo;
    }

    @Override
    public List<SkuPriceVo> getSkuPriceList(List<Long> skuIdList) {
        List<ProductSku> productSkuList = productSkuMapper.selectList(
                new LambdaQueryWrapper<ProductSku>()
                        .in(ProductSku::getId, skuIdList)
                        .select(ProductSku::getId, ProductSku::getSalePrice)
        );
        return productSkuList.stream().map(item -> {
            SkuPriceVo skuPrice = new SkuPriceVo();
            skuPrice.setSkuId(item.getId());
            skuPrice.setSalePrice(item.getSalePrice());
            return skuPrice;
        }).collect(Collectors.toList());
    }

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public void unlock(String orderNo) {

        //幂等性处理
        String key = "sku:unlock:" + orderNo;
        Boolean isFirst = redisTemplate.opsForValue().setIfAbsent(key, orderNo, 1, TimeUnit.HOURS);
        if(!isFirst) return;

        // 获取锁定库存的缓存信息
        String dataKey = "sku:lock:data:" + orderNo;
        List<SkuLockVo> skuLockVoList = (List<SkuLockVo>)this.redisTemplate.opsForValue().get(dataKey);
        if (CollectionUtils.isEmpty(skuLockVoList)){
            return;
        }

        // 解锁库存
        skuLockVoList.forEach(skuLockVo -> {
            int row = skuStockMapper.unlock(skuLockVo.getSkuId(), skuLockVo.getSkuNum());
        });

        // 解锁库存之后，删除锁定库存的缓存。
        this.redisTemplate.delete(dataKey);
    }

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public void minus(String orderNo) {
        //幂等性处理
        String key = "sku:minus:" + orderNo;
        //业务去重，防止重复消费
        Boolean isExist = redisTemplate.opsForValue().setIfAbsent(key, orderNo, 1, TimeUnit.HOURS);
        if(!isExist) return;

        // 获取锁定库存的缓存信息
        String dataKey = "sku:lock:data:" + orderNo;
        List<SkuLockVo> skuLockVoList = (List<SkuLockVo>)this.redisTemplate.opsForValue().get(dataKey);
        if (CollectionUtils.isEmpty(skuLockVoList)){
            return ;
        }

        // 减库存
        skuLockVoList.forEach(skuLockVo -> {
            int row = skuStockMapper.minus(skuLockVo.getSkuId(), skuLockVo.getSkuNum());
        });

        // 扣减库存之后，删除锁定库存的缓存。
        this.redisTemplate.delete(dataKey);
    }

}
